#include "util.h"

bool parse_url_2(char* const url, char* &req_url, std::map<char*,char*, classcomp> &para_map)
{
    if(url == NULL)
    {
        return false;
    }
    
    char *m_url = url;
    
    if(strncasecmp(url,"http://", 7) == 0)
    {
        m_url += 7;
    }
    
    
    m_url = strchr(m_url, '/');
    
    if(!m_url)
    {
        return false;
    }
    
    char *req_url_start = m_url;
    
    m_url = strchr(m_url, '?');
    
    if(!m_url)
    {
        req_url = req_url_start;
        return true;
    }
    else
    {
        *m_url = '\0';
        req_url = req_url_start;        
    } 
    
    //parse param
    while(true)
    { 
        // *m_url == '&' || *m_url == '?' 
        ++m_url;
        
        if(m_url[0] == '\0')
        {
            //return false;
            return true;
        }
         
        char *param_key_start = m_url;
        
        m_url = strchr(m_url, '=');
        
        if(!m_url)
        {
            //return false;
            return true;
        }
        else
        {
            *m_url = '\0';
            
            char* key = param_key_start;
            
            m_url++;
            
            char *param_value_start = m_url;
            
            m_url = strchr(m_url, '&');
        
            if(!m_url)
            {
                char *value = param_value_start;
                
                para_map[key] = value;
                
                return true;
            }
            else
            {
                *m_url = '\0';
                
                char *value = param_value_start;
                
                para_map[key] = value;
            }
               
        }
    }   
    
    return true;
}

bool get_file_name(char *real_name, const char *client_name)
{
    char ext[20] = "";
    ext[19] = '\0';
    
    const char *ext_start = strrchr(client_name,'.');
    
    if(ext_start != NULL)
    {
        strncpy(ext, ext_start, 19);
    }
    
    struct timeval timeval_instance;
    gettimeofday(&timeval_instance, NULL);
    
    sprintf(real_name, "%ld%ld", timeval_instance.tv_sec, timeval_instance.tv_usec);
    strcat(real_name, ext);
    
    return true;
}

#define BUF_SIZE 128

bool parse_file(const char* const file_path, std::map<std::string, std::string> &config_map)
{
	char buf[BUF_SIZE];
	
	memset(buf, '\0', BUF_SIZE);
	
	FILE *file_ptr = fopen(file_path, "r+");
	
	if(file_ptr == NULL)
	{
		return false;
	}
	
	char *temp_ptr = buf;
	char *key_ptr = NULL;
	char *value_ptr = NULL;
	int i = 0;
	
	while(fgets(buf, BUF_SIZE - 1, file_ptr) != NULL)
	{
		i++;
		temp_ptr = buf;
		
		if(strlen(buf) >= BUF_SIZE - 2)
		{
			printf("too long line %d : %s...\n", i, buf);
			goto error;
		}
		
		//filter space and tab
		while(*temp_ptr == ' ' || *temp_ptr == '\t')
		{
			temp_ptr++;
		}
		
		//jump space line and comment line
		if(*temp_ptr == '\n' || *temp_ptr == '#')
		{
			continue;
		}
		
		//parse key
		key_ptr = temp_ptr;
		while(*temp_ptr != '\n')
		{
			if(*temp_ptr == ' ' || *temp_ptr == '\t' || *temp_ptr == '=')
			{
				break;
			}
            
            if(*temp_ptr == '#')
            {
                printf("error config line %d : %s\n", i, buf);
                goto error;
            }
			
			temp_ptr++;
		}
		
		//key is null
		if(temp_ptr == key_ptr)
		{
			printf("error config line %d : %s\n", i, buf);
			goto error;
		}
		
		std::string key(key_ptr, temp_ptr - key_ptr);
		
		//filter space and tab
		while(*temp_ptr == ' ' || *temp_ptr == '\t')
		{
			temp_ptr++;
		}
		
		//the delimiter is not '='
		if(*temp_ptr == '\n' || *temp_ptr != '=')
		{
			printf("error config line %d : %s\n", i, buf);
			goto error;
		}
		
		temp_ptr++;
		
		//filter space and tab
		while(*temp_ptr == ' ' || *temp_ptr == '\t')
		{
			temp_ptr++;
		}
		
		//parse value
		value_ptr = temp_ptr;
		while(*temp_ptr != '\n')
		{
			if(*temp_ptr == ' ' || *temp_ptr == '\t' || *temp_ptr == '#')
			{
				break;
			}
			
			temp_ptr++;
		}
		
		std::string value(value_ptr, temp_ptr - value_ptr);
		
		//verify whether the value is continous or not
		while(*temp_ptr != '\n')
		{
            if(*temp_ptr == '#')
			{
				break;
			}
            
			if(*temp_ptr != ' ' && *temp_ptr != '\t')
			{
				printf("error config line %d : %s\n", i, buf);
				goto error;
			}
			
			temp_ptr++;
		}
		
		//into map
		config_map[key] = value;
	}
	
	fclose(file_ptr);
	return true;
	
	error:
		fclose(file_ptr);
		return false;
}

bool find_str(char* target, std::string key, std::map<std::string, std::string> &config_map, bool is_necessary)
{
    std::map<std::string, std::string>::iterator config_map_iter = config_map.begin();
    
    config_map_iter = config_map.find(key);
    
    if(config_map_iter == config_map.end())
    {
        if(is_necessary)
        {
            pr_debug("%s %s", key.c_str(),"is necessary config\n");
            return false;
        }
        
        return true;
    }
    
    strcpy(target, config_map_iter->second.c_str());
    return true;
}

bool find_bool(bool &target, std::string key, std::map<std::string, std::string> &config_map, bool is_necessary)
{
    std::map<std::string, std::string>::iterator config_map_iter = config_map.begin();
    
    config_map_iter = config_map.find(key);
    
    if(config_map_iter == config_map.end())
    {
        if(is_necessary)
        {
            pr_debug("%s %s", key.c_str(),"is necessary config\n");
            return false;
        }
        return true;
    }
    
    if(strcmp(config_map_iter->second.c_str(), "true")==0)
    {
        target = true;
    }
    
    return true;
}

bool find_int(int &target, std::string key, std::map<std::string, std::string> &config_map, bool is_necessary)
{
    std::map<std::string, std::string>::iterator config_map_iter = config_map.begin();
    
    config_map_iter = config_map.find(key);
    
    if(config_map_iter == config_map.end())
    {
        if(is_necessary)
        {
            pr_debug("%s %s\n", key.c_str(),"is necessary config");
            return false;
        }
        
        return true;
    }
    
    target = atoi(config_map_iter->second.c_str());
    if(target == 0)
    {
        pr_debug("%s %s\n", key.c_str(),"must be number larger than 0");
        return false;
    }
    
    return true;
}

bool set_param(const char* const file_path, std::map<std::string, std::string> &config_map)
{
    if(!parse_file(file_path,config_map))
    {
        pr_debug("parse file error\n");
        return false;
    }
    
    std::string doc_root_key("doc_root");
    
    std::string remote_ip_key("remote_ip");
    
    std::string remote_port_key("remote_port");
    
    std::string local_port_key("local_port");
    
    std::string is_use_forward_key("is_use_forward");
    
    if(!find_str(doc_root, doc_root_key, config_map, true))
    {
        pr_debug("parse doc_root error\n");
        return false;
    }
    
    if(!find_int(LOCAL_PORT, local_port_key, config_map, true))
    {
        pr_debug("parse LOCAL_PORT error\n");
        return false;
    }
    
    if(!find_bool(is_use_forward, is_use_forward_key, config_map, false))
    {
        pr_debug("parse is_use_forward error\n");
        return false;
    }
    
    if(is_use_forward)
    {
        if(!find_str(REMOTE_IP, remote_ip_key, config_map, true))
        {
            pr_debug("parse REMOTE_IP error\n");
            return false;
        }
        
        if(!find_int(REMOTE_PORT, remote_port_key, config_map, true))
        {
            pr_debug("parse REMOTE_PORT error\n");
            return false;
        }
    }
    
    return true;
}
